from pyduct.handlers import CookieFragmentBuilder, ProjectEntryFragmentBuilder, classOf, ResponseFragment, Boolean
from pyson.components import NumberField, StringField, DateField, BooleanField, Item, CheckItem, ArrayField, ProjectEntry
from java.lang import Boolean, IllegalArgumentException, Class
from java.util import ArrayList, Iterator, Collections
from argo.jdom import JsonNodeType
from scaladuct import MutablePropertyValue
from chloroform import TypedProjectEntry

class NumberFieldBuilder(CookieFragmentBuilder):
    def getCookieMessageFragmentClass(self, cookieGateway, property):
        if NumberFieldBuilder.isNumberClass(property.clazz()):
            class Fragment(NumberField):
                def __init__(self):
                    super(Fragment, self).__init__(property.name(), property.clazz().getName(), property.value())

            return Fragment
        else:
            return None


    def getCookieResponseFragmentClass(self, cookieGateway, property):
        if NumberFieldBuilder.isNumberClass(property.clazz()):
            class Fragment(ResponseFragment):
                def updateProperty(self, jsonNode):
                    if jsonNode.getType() == JsonNodeType.NUMBER:
                        return property.parse(jsonNode.getNumberValue())
                    else:
                        return property.parse(jsonNode.getStringValue())

            return Fragment
        else:
            return None


    @staticmethod
    def isNumberClass(clazz):
        return classOf("java.lang.Number").isAssignableFrom(clazz) or \
                clazz.getName() == "byte" or \
                clazz.getName() == "short" or \
                clazz.getName() == "int" or \
                clazz.getName() == "long" or \
                clazz.getName() == "float" or \
                clazz.getName() == "double"


class StringFieldBuilder(CookieFragmentBuilder):
    def getCookieMessageFragmentClass(self, cookieGateway, property):
        if classOf("java.lang.String") == property.clazz():
            class Fragment(StringField):
                def __init__(self):
                    super(Fragment, self).__init__(property.name(), property.value())

            return Fragment
        else:
            return None


    def getCookieResponseFragmentClass(self, cookieGateway, property):
        if classOf("java.lang.String") == property.clazz():
            class Fragment(ResponseFragment):
                def updateProperty(self, jsonNode):
                    return property.parse(jsonNode.getStringValue())

            return Fragment
        else:
            return None


class EnumFieldBuilder(CookieFragmentBuilder):
    def getCookieMessageFragmentClass(self, cookieGateway, property):
        if property.clazz().isEnum():
            class Fragment(StringField):
                def __init__(self):
                    super(Fragment, self).__init__(property.name(), "%s" % property.value())

            return Fragment
        else:
            return None


    def getCookieResponseFragmentClass(self, cookieGateway, property):
        if property.clazz().isEnum():
            class Fragment(ResponseFragment):
                def updateProperty(self, jsonNode):
                    return property.parse(jsonNode.getStringValue())

            return Fragment
        else:
            return None

class BooleanFieldBuilder(CookieFragmentBuilder):
    def getCookieMessageFragmentClass(self, cookieGateway, property):
        if classOf("java.lang.Boolean") == property.clazz() or \
        "boolean" == property.clazz().getName():
            class Fragment(BooleanField):
                def __init__(self):
                    super(Fragment, self).__init__(property.name(), property.value())

            return Fragment
        else:
            return None


    def getCookieResponseFragmentClass(self, cookieGateway, property):
        if classOf("java.lang.Boolean") == property.clazz() or \
        "boolean" == property.clazz().getName():
            class Fragment(ResponseFragment):
                def updateProperty(self, jsonNode):
                    if jsonNode.getType() == JsonNodeType.TRUE:
                        return property.update(Boolean.TRUE)
                    elif jsonNode.getType() == JsonNodeType.FALSE:
                        return property.update(Boolean.FALSE)
                    else:
                        return property.update(jsonNode.getStringValue())

            return Fragment
        else:
            return None

class ListFieldBuilder(CookieFragmentBuilder):
    def getCookieMessageFragmentClass(self, cookieGateway, property):
        if classOf("java.util.List").isAssignableFrom(property.clazz()):
            class Fragment(ArrayField):
                def __init__(self):
                    if property.value() is not None:
                        super(Fragment, self).__init__(property.name(), property.value())
                    else:
                        super(Fragment, self).__init__(property.name(), Collections.emptyList())
                    #                    if property.value() is not None and not property.value().isEmpty():
                    #                        super(Fragment, self).__init__(property.name(), "%s" % property.value().get(0))
                    #                    else:
                    #                        super(Fragment, self).__init__(property.name(), None)

            return Fragment
        else:
            return None


    def getCookieResponseFragmentClass(self, cookieGateway, property):
        def convertToListOfStrings(nodes):
            result = ArrayList()
            iter = nodes.iterator()
            while iter.hasNext():
                node = iter.next()
                if node.getType() == JsonNodeType.NUMBER:
                    result.add(node.getNumberValue())
                else:
                    result.add(node.getStringValue())
            return result

        if classOf("java.util.List").isAssignableFrom(property.clazz()):
            class Fragment(ResponseFragment):
                def updateProperty(self, jsonNode):
                    if jsonNode.getType() == JsonNodeType.STRING:
                        return property.parse(jsonNode.getStringValue())
                    else:
                        listOfStrings = convertToListOfStrings(jsonNode.getArrayNode())
                        return property.parse(listOfStrings)

            return Fragment
        else:
            return None

class DateFieldBuilder(CookieFragmentBuilder):
    def getCookieMessageFragmentClass(self, cookieGateway, property):
        if classOf("java.util.Date").isAssignableFrom(property.clazz()):
            class Fragment(DateField):
                def __init__(self):
                    super(Fragment, self).__init__(property.name(), property.value())

            return Fragment
        else:
            return None


    def getCookieResponseFragmentClass(self, cookieGateway, property):
        if classOf("java.util.Date").isAssignableFrom(property.clazz()):
            class Fragment(ResponseFragment):
                def updateProperty(self, jsonNode):
                    return property.parse(jsonNode.getStringValue())

            return Fragment
        else:
            return None

class MenuItemBuilder(CookieFragmentBuilder):
    def getCookieMessageFragmentClass(self, cookieGateway, hint):
        class Fragment(Item):
            def __init__(self):
                super(Fragment, self).__init__(hint.name(), hint.name())

        return Fragment

class CheckMenuItemBuilder(CookieFragmentBuilder): # todo: merge it with the BooleanField
    def isCheckedHint(self, hint):
        return isinstance(hint, MutablePropertyValue) and \
        (hint.clazz().getName() == "boolean" or \
        hint.clazz().getName() == "java.lang.Boolean")


    def getCookieMessageFragmentClass(self, cookieGateway, hint):
        if self.isCheckedHint(hint):
            class Fragment(CheckItem):
                def __init__(self):
                    super(Fragment, self).__init__(hint.name(), hint.name())
                    self.checked = hint.value()

            return Fragment
        else:
            return None


    def getCookieResponseFragmentClass(self, cookieGateway, hint):
        if self.isCheckedHint(hint):
            class Fragment(ResponseFragment):
                def updateProperty(self, jsonNode):
                    if jsonNode.getType() == JsonNodeType.TRUE:
                        return hint.update(Boolean.TRUE)
                    elif jsonNode.getType() == JsonNodeType.FALSE:
                        return hint.update(Boolean.FALSE)
                    else:
                        return hint.update(jsonNode.getStringValue())

            return Fragment
        else:
            return None


class ProjectEntryBuilder(ProjectEntryFragmentBuilder):

    def getProjectEntryFragmentClass(self, buildContext, projectEntry):
        class Fragment(ProjectEntry):
            def __init__(self):
                entryType = projectEntry.getEntryType()
                if isinstance(entryType, Class):
                    entryTypeName = entryType.getName()
                else:
                    entryTypeName = `entryType`

                if projectEntry.extensions().isEmpty():
                    exts = ()
                else:
                    exts = buildContext.handler.getBuildersForProjectEntries(buildContext, projectEntry.extensions())

                super(Fragment, self).__init__(projectEntry.fullName(), entryTypeName, exts)

        return Fragment

def getBuilders():
    return (EnumFieldBuilder, DateFieldBuilder, ListFieldBuilder, BooleanFieldBuilder, NumberFieldBuilder, StringFieldBuilder)

def getHintBuilders():
    return (CheckMenuItemBuilder, MenuItemBuilder)

def getProjectEntryBuilders():
    return (ProjectEntryBuilder,)
